package munci.old.know;

import java.util.LinkedList;

import munci.old.know.words.Word;
import munci.old.use.DynamicCompiler;
import munci.old.use.Visitor;


/**
 * @author Giles Burgess
 *
 */
public class Dictionary {
	
	/**
	 * Interface for dictionary bookmark
	 */
	public interface Bookmark {
		public void forget();
	}
	
	private final DynamicCompiler compiler;

	private final LinkedList<Word> entries = new LinkedList<Word>();
	
	public Dictionary(ClassLoader ldr, String path) {
		this.compiler = new DynamicCompiler();
	}
	
	/**
	 * @return bookmark for current dictionary state
	 */
	public Bookmark bookmark() {
		final Word mark = entries.size() > 0? entries.get(0) : null;
		return new Bookmark() {
			public void forget() {
				remove(mark);
			}
		};
	}

	/**
	 * Forgets all words added since the specified bookmark
	 * @param bookmark
	 */
	private void remove(Word bookmark) {
		if (bookmark == null) {
			entries.clear();
		} else {
			entries.subList(0, entries.indexOf(bookmark)).clear();
		}
	}
	
	public Class<?> compile(String source, String name) throws Exception {
		return compiler.compile(source, name);
	}
	
	public Class<?> getClass(String type) throws ClassNotFoundException {
		return compiler.getClass(type);
	}

	/**
	 * Adds words from the specified class to the dicionary
	 * @param type fully qualified name of class
	 * @return this
	 * @throws ClassNotFoundException
	 */
	public Dictionary learn(String type) throws ClassNotFoundException {
		return learn(compiler.getClass(type));
	}
	
	public Dictionary learn(Class<?> cl) {
		for (Word word : Word.words(cl)) {
			entries.add(0, word);
		}
		return this;
	}
	
	public Dictionary learn(Word word) {
		entries.add(0, word);
		return this;
	}
	
	public boolean search(String name, Visitor<Word> visitor) {
		for (Word entry : entries) {
			if (entry.name.equals(name) && visitor.visit(entry)) {
				return true;
			}
		}
		return false;
	}
	
	public Word find(String name) {
		for (Word entry : entries) {
			if (entry.name.equals(name)) {
				return entry;
			}
		}
		return null;
	}
	
	public boolean visit(Visitor<Word> visitor) {
		for (Word entry : entries) {
			if (visitor.visit(entry)) {
				return true;
			}
		}
		return false;
	}
}
